package com.example.financechain.service.Impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.financechain.Utils.GatewayUtilss;
import com.example.financechain.Utils.JsonData;
import com.example.financechain.Utils.UUIDUtils;
import com.example.financechain.Utils.UserThreadLocal;
import com.example.financechain.config.CacheKeyManager;
import com.example.financechain.domain.DTO.AuditParam;
import com.example.financechain.domain.VO.FinancingVo;
import com.example.financechain.domain.entity.Financing;
import com.example.financechain.domain.entity.Role;
import com.example.financechain.domain.entity.Status;
import com.example.financechain.mapper.FinancingMapper;
import com.example.financechain.service.IBlockexploreService;
import com.example.financechain.service.IFinancingService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.financechain.service.IStatusService;
import lombok.extern.slf4j.Slf4j;
import org.hyperledger.fabric.gateway.*;
import org.hyperledger.fabric.sdk.Channel;
import org.hyperledger.fabric.sdk.Peer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.cert.CertificateException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.TimeoutException;

/**
 * <p>
 * 融资信息表 服务实现类
 * </p>
 *
 * @author yy
 * @since 2023-04-19
 */
@Service
@Slf4j
public class FinancingServiceImpl extends ServiceImpl<FinancingMapper, Financing> implements IFinancingService {


    @Autowired
    private IStatusService iStatusService;

    @Autowired
    private IBlockexploreService iBlockexploreService;

    @Autowired
    GatewayUtilss gatewayUtilss;

//    @Autowired
//    private FinancingMapper financingMapper;

    @Override
    @Transactional
    public JsonData createfiance(Financing financing) {



        //Status status = new Status();
        //1表示融资项目创建了 资质完善步骤中 0表示该步骤审核中
        // synchronized (UserThreadLocal.get().getRoleId().toString().intern()){
        Status status =  createStatus(1, 0, null, financing.getFinancingId());

        //}


        //创建融资项目编号num
        String financenum = CacheKeyManager.FL+UUIDUtils.getUUID(8);

        //创建融资项目
        financing.setFinancingnum(financenum);
        financing.setCreateTime(LocalDateTime.now());
        financing.setStatus(status.getProgressid());

        boolean success = save(financing);



        if (success){
            financing = getById(financing.getFinancingId());
        }
        //还应该将保存好的数据返回去
        return JsonData.buildSuccess(financing,"保存成功");
    }



    @Override
    public JsonData Completeinformation(Financing financing) {

       // Status status = createStatus(2, 0, null);
        //financing.setStatus(status.getProgressid());
        QueryWrapper<Financing> queryWrapper =new QueryWrapper<>();
        queryWrapper.eq("financing_id",financing.getFinancingId());
        boolean success = update(financing, queryWrapper);

        // 拿到最新的状态
        Financing financing1 = getById(financing.getFinancingId());
        Status status = iStatusService.getById(financing1.getStatus());

        if (success){
            //暂时未开发完
            Long progressid = createStatus(status.getProgress(), 0, null, financing1.getFinancingId()).getProgressid();
            financing1.setStatus(progressid);
            update().setEntity(financing1);

        }




        return JsonData.buildSuccess(null,"提交成功");
    }

    /**
     * 查找跟申请融资公司的融资列表
     * @return
     */
    @Override
    public JsonData querymessage() {
        Role role = UserThreadLocal.get();

        LambdaQueryWrapper<Financing> lambdaQueryWrapper =new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Financing::getEnterpriseName,role.getRoleName());

        List<Financing> financingList = list(lambdaQueryWrapper);

        return JsonData.buildSuccess(financingList);
    }

    @Override
    public JsonData queryfinance() {
        Role role = UserThreadLocal.get();
        List<Financing> list = new ArrayList<>();
        //专门为金融机构的审核
//        if (!role.getRoleCertification().equals("finance-org")){
//
//            return JsonData.buildError("无权进行审核");
//        }

        //查找/跟银行有关的融资项目
        QueryWrapper<Financing> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("bank_name",role.getRoleName());
        list = list(queryWrapper);

        List<FinancingVo> financingVoList =new ArrayList<>();

        for (Financing f: list
             ) {
            Status s = iStatusService.getById(f.getStatus());

            FinancingVo financingVo =new FinancingVo();
            if (s.getProgress()==4&&s.getProgressStatus()==2){
                financingVo.setSearchstatus(CacheKeyManager.COMPLETED);
            }else {
                financingVo.setSearchstatus(CacheKeyManager.WAITING);
            }
            financingVo.setFinancing(f);
            System.out.println(f.getCreateTime());

            financingVoList.add(financingVo);
        }

        return  JsonData.buildSuccess(financingVoList);

    }


    @Override
    public JsonData queryfinancebyId(Long id) {
       // FinancingVo financingVo = financingMapper.queryfinancebyId();
        Financing financing = getById(id);

//        QueryWrapper<Status> queryWrapper =new QueryWrapper<>();
//        queryWrapper.eq("financing_id",financing.getFinancingId());
        //List<Status> statusList = iStatusService.list(queryWrapper);
        Status status = iStatusService.getById(financing.getStatus());

        FinancingVo financingVo =new FinancingVo();
        financingVo.setFinancing(financing);
        financingVo.setStatus(status);


        return  JsonData.buildSuccess(financingVo);
    }

    @Override
    public JsonData queryfinancingexsit() {
        String enterpriseName = UserThreadLocal.get().getRoleName();
        LambdaQueryWrapper<Financing> lambdaQueryWrapper =new LambdaQueryWrapper<>();

        lambdaQueryWrapper.eq(Financing::getEnterpriseName,enterpriseName);

        List<Financing> financingList = list(lambdaQueryWrapper);

        FinancingVo financingVo =new FinancingVo();
        for (Financing f: financingList
             ) {
            Status status = iStatusService.getById(f.getStatus());
            if (status.getProgress()!=4){
                financingVo.setFinancing(f);
                financingVo.setStatus(status);
                break;
            }else {
                if (status.getProgressStatus()!=2){
                    financingVo.setFinancing(f);
                    financingVo.setStatus(status);
                    break;
                }
            }
        }
        return JsonData.buildSuccess(financingVo);

    }

    @Override
    public JsonData auditResult(AuditParam auditParam) {

        Financing financing = getById(auditParam.getFinancingId());

        if (financing==null){
            return JsonData.buildError("融资ID不能为空");
        }
        //当前融资项目的状态
        Status status =iStatusService.getById(financing.getStatus());

        //如果审核通过
        if(auditParam.getProgressStatus()==2){
            //如果审核通过 就创建新状态 将当前进度+1 并且状态修改为展开中 并返回修改结果
            Long progressid = createStatus(status.getProgress() + 1, 3, auditParam.getResult(),auditParam.getFinancingId()).getProgressid();

            UpdateWrapper<Financing> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().eq(Financing::getFinancingId,auditParam.getFinancingId()).set(Financing::getStatus,progressid);
            update(updateWrapper);



            return JsonData.buildSuccess(null,"审核已通过,等待企业提交信息");
        }else {

            Long progressid = createStatus(status.getProgress() , 1, auditParam.getResult(),auditParam.getFinancingId()).getProgressid();

            UpdateWrapper<Financing> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().eq(Financing::getFinancingId,auditParam.getFinancingId()).set(Financing::getStatus,progressid);
            update(updateWrapper);

            return JsonData.buildSuccess(null,"已驳回");

        }


    }

    @Override
    public JsonData acceptContrac(Financing financing) throws CertificateException, IOException, InvalidKeyException, ContractException, InterruptedException, TimeoutException {

        Role role = UserThreadLocal.get();
        financing = getById(financing.getFinancingId());

//        UpdateWrapper<Financing> updateWrapper =new UpdateWrapper<>();
//        updateWrapper.lambda().eq(Financing::getFinancingId,financing.getFinancingId()).set(Financing::getContractAddress,financing.getContractAddress());
//        boolean success = update(financing, updateWrapper);


        financing = getById(financing.getFinancingId());
        String txid = hyperchain(financing,role);
            //暂时未开发完
        Long progressid = createStatus(4, 2, null, financing.getFinancingId()).getProgressid();
        financing.setStatus(progressid);
        financing.setTxid(txid);

        UpdateWrapper<Financing> updateWrapper =new UpdateWrapper<>();
        updateWrapper.lambda().eq(Financing::getFinancingId,financing.getFinancingId()).set(Financing::getContractAddress,financing.getContractAddress()).set(Financing::getTxid,txid);
        boolean success = update(financing, updateWrapper);

        if (!success){
            return JsonData.buildError("上链失败");
        }

        iBlockexploreService.updateBlockstore();

        return JsonData.buildSuccess(txid,"签约成功，产生区块");
    }

    @Override
    public JsonData contracting(Financing financing) {

        UpdateWrapper<Financing> updateWrapper =new UpdateWrapper<>();
        updateWrapper.lambda().eq(Financing::getFinancingId,financing.getFinancingId()).set(Financing::getContractAddress,financing.getContractAddress());
        boolean success = update(financing, updateWrapper);


        financing = getById(financing.getFinancingId());
        if (success){
            //暂时未开发完
            Long progressid = createStatus(4, 3, null, financing.getFinancingId()).getProgressid();
            financing.setStatus(progressid);
            update().setEntity(financing);

        }
        return JsonData.buildSuccess(null,"等待企业接受签约");
    }

    /**
     * 创建状态用于两边检查
     * @param progress
     * @param progressStatus
     * @param result
     */
    private Status createStatus(int progress,int progressStatus,String result,Long financingid){
        Status status = new Status();

        status.setProgress(progress);
        status.setProgressStatus(progressStatus);
        status.setResult(result);
        status.setFinancingId(financingid);

        iStatusService.save(status);

        return status;
    }

    /**
     * 交易上链
     * @param
     * @return
     */
    private String hyperchain(Financing financing,Role role) throws CertificateException, IOException, InvalidKeyException, ContractException, InterruptedException, TimeoutException {
        try (Gateway gateway = gatewayUtilss.build(role).connect()) {
            // Get the network and chaincode
            Network network = gateway.getNetwork("energycarchannel");
            Contract contract = network.getContract("financecontract");

            // Set endorsement policy
            EnumSet<Peer.PeerRole> roles = EnumSet.of(Peer.PeerRole.ENDORSING_PEER);
            // ...

            // Submit transaction
            Transaction transaction = contract.createTransaction("RecordContract")
                    .setEndorsingPeers(network.getChannel().getPeers(EnumSet.of(Peer.PeerRole.ENDORSING_PEER)));
            transaction.submit(financing.getFinancingnum(), financing.getEnterpriseName(), financing.getBankName(), LocalDateTime.now().toString(), financing.getContractAddress());

            // Wait for transaction to complete and print transaction ID
            String txid = transaction.getTransactionId();
            log.info("++++++++++ txId:"+txid+"++++++++++++");
//            System.out.println("txId:" + txid);

            return txid;
        } catch (Exception e) {
            // Handle exceptions
            e.printStackTrace();
            return null;
        }
    }

}
